package container;

import java.util.Arrays;
import java.util.List;

/**
 * https://blog.csdn.net/f641385712/article/details/81981095
 */
public class T01_Arrays {
    static Integer[] arrayTest = {6, 1, 9, 2, 5, 7, 6, 10, 6, 12};

    public static void main(String[] args) {
        sort();
    }

    /**
     * sort 和 parallelSort：算法精华
     * parallelSort 是 java8 中新出的一种排序 API，这是一种并行排序，Arrays.parallelSort 使用了 Java7 的 Fork/Join 框架使排序任务可以
     * 在线程池中的多个线程中进行，Fork/Join 实现了一种任务窃取算法，一个闲置的线程可以窃取其他线程的闲置任务进行处理。
     * 性能对比结论：数组数据量越大，parallelSort 的优势就越明显。
     * spliterator：最优的遍历，这是 JDK 为了高级遍历数组而提供的一个方法
     * jdk 源码中写的排序算法都很精简，值得学习
     */
    public static void sort() {
        Arrays.sort(arrayTest);
        System.out.println(Arrays.toString(arrayTest));
    }

    /**
     * parallelPrefix：二元迭代，对原数组内容进行二元操作
     * 就是拿前面的结果，和当前元素做运算。这个运算规则，由我们自己来定义。
     */
    public static void parallelPrefix() {
        Integer[] arrayPP1 = Arrays.copyOf(arrayTest, arrayTest.length);
        System.out.println(Arrays.toString(arrayPP1)); // [6, 1, 9, 2, 5, 7, 6, 10, 6, 12]

        // 二元迭代，对原数组内容进行二元操作
        Arrays.parallelPrefix(arrayPP1, (x, y) -> x * y);
        System.out.println(Arrays.toString(arrayPP1)); // [6, 6, 54, 108, 540, 3780, 22680, 226800, 1360800, 16329600]

        // 在指定下标范围内，对原数组内容进行二元操作，下标含头不含尾
        Integer[] arrayPP2 = Arrays.copyOf(arrayTest, arrayTest.length);
        Arrays.parallelPrefix(arrayPP2, 0, 5, (x, y) -> x * y);
        System.out.println(Arrays.toString(arrayPP2)); // [6, 6, 54, 108, 540, 7, 6, 10, 6, 12]
    }

    public static void setAll() {
        Integer[] setAllArr = Arrays.copyOf(arrayTest, arrayTest.length);
        // 一个数组全部做表达式操作
        System.out.println(Arrays.toString(setAllArr)); // [6, 1, 9, 2, 5, 7, 6, 10, 6, 12]
        // 一定要注意，此处我们需要用 setAllArr[i] 才是我们想要的结果
        Arrays.setAll(setAllArr, i -> setAllArr[i] * 3); // 回调给我们的是角标，而不是值
        // Arrays.setAll(setAllArr, i -> i * 3);
        System.out.println(Arrays.toString(setAllArr)); // [18, 3, 27, 6, 15, 21, 18, 30, 18, 36]
    }

    /**
     * fill：将一个数组全部置为 val ，或在下标范围内将数组置为 val
     */
    public static void fill() {
        // Integer[] arrayTest = new Integer[5];
        // 将一个数组置为 val(5)
        Arrays.fill(arrayTest, 5);
        System.out.println(Arrays.toString(arrayTest)); // [5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
        // 将一个数组指定范围内置为 val(10)  含头不含尾
        Arrays.fill(arrayTest, 2, 3, 10); // 通过角标 可以控制可以批量换值
        System.out.println(Arrays.toString(arrayTest)); // [5, 5, 10, 5, 5, 5, 5, 5, 5, 5]
    }

    public static void deepToString() {
        // 一维数组 toString
        System.out.println(Arrays.toString(arrayTest));
        Integer[][] stuGrades = {{1, 3, 5, 7, 9}, {2, 4, 6, 8}, {1, 5, 10}};
        // 二维数组 toString
        System.out.println(Arrays.deepToString(stuGrades));
    }

    /**
     * equals 和 deepEquals：比较数组内容是否相等
     * equals：比较一位数组内容
     * deepEquals：比较二维数组内容
     */
    public static void equals() {
        // 定义一个二维数组  学生成绩
        Integer[][] stuGrades = {{1, 3, 5, 7, 9}, {2, 4, 6, 8}, {1, 5, 10}};
        Integer[] equals1 = Arrays.copyOf(arrayTest, arrayTest.length); // 完整拷贝
        // 比较一维数组内容是否相等
        System.out.println(Arrays.equals(equals1, arrayTest)); // true

        Integer[][] equals2 = Arrays.copyOf(stuGrades, stuGrades.length);
        // 比较二维数组内容是否相等
        System.out.println(Arrays.deepEquals(stuGrades, equals2)); // true
    }

    /**
     * copyOf 和 copyOfRange：复制、截取数组
     */
    public static void copyOf() {
        // 复制出新的数组，复制长度由 newLength 决定，长度可大于被复制数组的长度，也可以小于
        Integer[] copyArray1 = Arrays.copyOf(arrayTest, 2); // 长度小于
        Integer[] copyArray11 = Arrays.copyOf(arrayTest, 15); // 长度大于
        System.out.println(Arrays.toString(copyArray1)); // [6, 1]
        System.out.println(Arrays.toString(copyArray11)); // [6, 1, 9, 2, 5, 7, 6, 10, 6, 12, null, null, null, null, null]
        // 复制指定下标范围内的值,含头不含尾（这是通用规则）
        Integer[] copyArray2 = Arrays.copyOfRange(arrayTest, 2, 7); // 截取部分
        System.out.println(Arrays.toString(copyArray2));
    }

    /**
     * 二分法查找，数组必须有序
     * 必须在进行此调用之前对数组进行排序（sort 方法）。
     * 如果没有对数组进行排序，则结果是不明确的。
     * 如果数组包含多个带有指定值的元素，则无法保证找到的是哪一个。
     */
    public static void binarySearch() {
        int[] a = new int[]{1, 3, 4, 6, 8, 9};
        int x1 = Arrays.binarySearch(a, 5);
        int x2 = Arrays.binarySearch(a, 4);
        int x3 = Arrays.binarySearch(a, 0);
        int x4 = Arrays.binarySearch(a, 1);
        System.out.println(x1); // -4 不存在时从 1 开始(因为是有序的  所有有角标)
        System.out.println(x2); // 2
        System.out.println(x3); // -1 不存在时从 1 开始，所以值是 -1，不是 -0
        System.out.println(x4); // 0 存在时，从 0 开始
    }

    /**
     * 快速构建一个 list，它是自己内部实现的一个 ArrayList，使用起来个 ArrayList 差不多。但是需要注意：它的长度不可变，不能调用 remove 方法
     */
    public static void asList() {
        List<Integer> list = Arrays.asList(1, 2, 3);
        list.remove(1); // java.lang.UnsupportedOperationException
    }
}
